
#include <galite/garandom.h>
#include <galite/GAPopulation.h>

#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

#include <unistd.h>
#include <omp.h>
#include <time.h>
#include <string.h>
#include <assert.h>
#include <math.h>

#ifndef ARRAYGENOME_CLASS
#define ARRAYGENOME_CLASS

class ArrayGenome : public GAGenome 
 {

  public:
    static int genomeId;

  private:

    vector<double> xgenome;	

  public:

    static void Init(GAGenome&);
    static int Mutate(GAGenome&, float);
    static float Evaluate(GAGenome&);
    static int Cross(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*);

    int genomeNo;

  public:

    ArrayGenome(int n) : GAGenome(Init, Mutate)
      { 
	evaluator(Evaluate); 
	crossover(Cross);
	mutator(Mutate);
	initializer(Init);

	xgenome.resize(n);	
	fill(xgenome.begin(), xgenome.end(), 0);

	setAlive();
	invalidate();
	genomeNo = genomeId++;
	cout << " Chromosome " << genomeNo << " created" << endl;
      }

    ArrayGenome(const ArrayGenome& orig) { 
	copy(orig); 

	setAlive();
	genomeNo = genomeId++;
      }

    ~ArrayGenome() {
      }

    double GARandomDouble()
	{
		return randObj->GARandomDouble();
	}


    int GARandomInt(int min, int max)
	{
		return randObj->GARandomInt(min, max);
	}

    bool GAFlipCoin(double f)
	{
		return randObj->GAFlipCoin(f);
	}

   int size()
	{
	return xgenome.size();
	}

   void newId()
	{
	genomeNo = genomeId++;
	}

   int getId() const
	{
	return genomeNo;
	}

    double diversity(const GAPopulation& pop);

    int initialize(); 

    int mutate(double p); 

    void getArrayGenome(double *x) const
	{
	for (int i=0; i<xgenome.size(); i++)
		x[i] = xgenome[i];
	}

    ArrayGenome& operator=(const GAGenome& orig)
      {
      if(&orig != this) 
	  copy(orig);
      return *this;
      }

    double getXGene(int i) const
	{
	assert(i < xgenome.size());
	return xgenome[i];
	}

    int equal(const vector<double>& x) const
	{
	  for (int i=0; i<xgenome.size(); i++)
		{
		double dx = xgenome[i] - x[i];
		if (dx > 0.00001)
		    return 0;
		}	
	  return 1;
	}

    int equal(const GAGenome& genome) const
      {
	  ArrayGenome& vgenome = (ArrayGenome&) genome;

	  int res = vgenome.equal(xgenome);
	  if (!res) return 0;
	  return 1;
      }

    GAGenome* clone() const 
      {
	return new ArrayGenome(*this);
      }

    void copy(vector<double>& x) const
      {
	 std::copy(xgenome.begin(), xgenome.end(), x.begin());
      }

    void copy(vector<double>& x, int st, int en) const
      {
	 std::copy(xgenome.begin()+st, xgenome.begin()+en, x.begin());
      }

    void copyX(const ArrayGenome& sol, int n0, int n1)
	{
	 sol.copy(xgenome, n0, n1);
	}

    void copy(const GAGenome& orig) 
      {
      GAGenome::copy(orig);  // this copies all of the base genome parts
      ArrayGenome& genome = (ArrayGenome&) orig;
      int n = genome.size();
      xgenome.resize(n); 	
      genome.copy(xgenome);
      genomeNo = genome.genomeNo;
      }

   double diff(const vector<double>& x) const;

   double diff(const ArrayGenome& other) const;

   double diff(const ArrayGenome* other) const;
    
   friend ostream& operator<<(ostream& Ostr, const ArrayGenome& sol);
};
#endif
